﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace Ddavidlib.GameEngine
{
    public enum KeyState
    {
        kNotBeTraced,
        kReleased,
        kPressed,
        kPressedThenReleased,
    }

    public class KeyStateStorage
    {
        public KeyState keyState { set; get; }

        public KeyStateStorage()
        {
            keyState = KeyState.kReleased;
        }
    }

    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class KeyStateTracer : LogGameComponent
    {
        Dictionary<Keys, KeyStateStorage> keyStateList;

        public KeyStateTracer(Game game, string name, LogSystem usedLogSystem)
            : base(game, name, usedLogSystem)
        {
            // TODO: Construct any child components here
            keyStateList = new Dictionary<Keys, KeyStateStorage>();
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here
            foreach (KeyValuePair<Keys, KeyStateStorage> keyDownAndUp in keyStateList)
            {
                if (keyDownAndUp.Value.keyState == KeyState.kReleased)
                {
                    if (Keyboard.GetState().IsKeyDown(keyDownAndUp.Key))
                    {
                        keyDownAndUp.Value.keyState = KeyState.kPressed;
                        Log("Key " + keyDownAndUp.Key.ToString() + " is Pressed.");
                    }
                }
                else if (keyDownAndUp.Value.keyState == KeyState.kPressed)
                {
                    if (Keyboard.GetState().IsKeyUp(keyDownAndUp.Key))
                    {
                        keyDownAndUp.Value.keyState = KeyState.kPressedThenReleased;
                        Log("Key " + keyDownAndUp.Key.ToString() + " is PressedThenReleased.");
                    }
                }
                else if (keyDownAndUp.Value.keyState == KeyState.kPressedThenReleased)
                {
                    if (Keyboard.GetState().IsKeyUp(keyDownAndUp.Key))
                    {
                        keyDownAndUp.Value.keyState = KeyState.kReleased;
                        Log("Key " + keyDownAndUp.Key.ToString() + " is Released.");
                    }
                    else if (Keyboard.GetState().IsKeyDown(keyDownAndUp.Key))
                    {
                        keyDownAndUp.Value.keyState = KeyState.kPressed;
                        Log("Key " + keyDownAndUp.Key.ToString() + " is Pressed.");
                    }
                }
            }
            
            base.Update(gameTime);
        }

        public void AddTracedKey(Keys key)
        {
            if (!keyStateList.ContainsKey(key))
            {
                keyStateList.Add(key, new KeyStateStorage());
            }
        }

        public void AddAllTracedKey()
        {
            keyStateList.Clear();
            foreach (Keys key in Keys.GetValues(typeof(Keys)))
            {
                AddTracedKey(key);
            }
        }

        public void RemoveTracedKey(Keys key)
        {
            keyStateList.Remove(key);
        }

        public KeyState GetKeyState(Keys key)
        {
            if (keyStateList.ContainsKey(key))
            {
                return keyStateList[key].keyState;
            }
            else
            {
                return KeyState.kNotBeTraced;
            }
        }

        public bool IsKeyComboPressed(List<Keys> keyCombo)
        {
            bool combo = true;
            string comboString = "";

            foreach (Keys key in keyCombo)
            {
                if (!keyStateList.ContainsKey(key))
                {
                    combo = false;
                }
                else if (keyStateList.ContainsKey(key) && keyStateList[key].keyState != KeyState.kPressed)
                {
                    combo = false;
                }
            }

            if (combo)
            {
                foreach (Keys key in keyCombo)
                {
                    comboString += key.ToString() + " ";
                }
                Log("Key Combo " + comboString + "is Pressed.");
            }

            return combo;
        }
    }
}
